package com.wayz.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.wayz.constants.CTaskType;
import com.wayz.entity.pojo.base.DPlayAlert;
import com.wayz.entity.pojo.base.DPlayController;
import com.wayz.entity.pojo.menu.DPlayMenu;
import com.wayz.entity.pojo.play.DPlayHeartbeat;
import com.wayz.entity.redis.play.RPlayer;
import com.wayz.entity.vo.menu.MenuVo;
import com.wayz.entity.vo.task.TaskVo;
import com.wayz.exception.ExceptionCode;
import com.wayz.exception.WayzException;
import com.wayz.mapper.DPlayAlertDAO;
import com.wayz.mapper.DPlayControllerDAO;
import com.wayz.mapper.DRealtimeLiveDAO;
import com.wayz.rabbitmq.MqDefinition;
import com.wayz.redis.RPlayHeartbeatId;
import com.wayz.redis.RPlayerHeartbeatRank;
import com.wayz.redis.RPlayerObject;
import com.wayz.util.StringUtil;
import com.wayz.util.TimeHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 播控接口服务实现类
 * 
 * @author wade.liu@wayz.ai
 *
 */
@Service("playApiService")
@org.apache.dubbo.config.annotation.Service(version = "1.0.0", protocol = "dubbo")
@RefreshScope
public class PlayApiServiceImpl implements PlayApiService {

    /** 播控报警信息DAO */
    @Resource(name = "dPlayAlertDAO")
    private DPlayAlertDAO dPlayAlertDAO = null;
    /** 播放控制器DAO */
    @Resource(name = "dPlayControllerDAO")
    private DPlayControllerDAO dPlayControllerDAO = null;
    /** 实时直播DAO */
    @Resource(name = "dRealtimeLiveDAO")
    private DRealtimeLiveDAO dRealtimeLiveDAO = null;

    /** 对象相关 */
    /** 播控器对象 */
    @Resource(name = "rPlayerObject")
    private RPlayerObject rPlayerObject = null;
    /** 播控器心跳标识 */
    @Resource(name = "rPlayHeartbeatId")
    private RPlayHeartbeatId rPlayHeartbeatId = null;
    /** 播控心跳时间排名 */
    @Resource(name = "rPlayerHeartbeatRank")
    private RPlayerHeartbeatRank rPlayerHeartbeatRank = null;

    /** rabbitMq模板 */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /** 节目单临时存放路径 */
    @Value("${play.menu.savePath}")
    private String playMenuSavePath = null;


    /** 日志 */
    private static final Logger LOGGER = LoggerFactory.getLogger(PlayApiServiceImpl.class);

    /**
     * 获取播放任务
     *
     * @param mac 播控设备有线网卡MAC地址
     * @param osType 操作系统类型(1:ios; 2:Android;3:windows)
     * @param imei 播控设备IMEI号
     * @param version 本机播控系统软件版本
     * @param communicationType 通信类型(1:WIFI; 2:GSM; 3:有线)
     * @param isInitial 是否为初始(true为初始; false为正常执行任务)
     * @param ipAddr 远程主机IP
     * @param ts 系统时间戳(精确到秒)
     * @param st 当前状态(0:空闲;1:正常播放;2:正在更新操作系统; 3:正在更新播放器程序)
     * @param planId 当前播放的节目单标识
     * @param menuId 当前播放节目单标识
     * @param signal 信号强度
     * @return 任务列表
     */
    @Override
    public List<TaskVo> getTask(String mac, Short osType, String imei, String version, Short communicationType,
                                Boolean isInitial, String ipAddr, Long ts, Short st, Long planId, Long menuId, Integer signal)
            throws WayzException {

        // 初始化
        List<TaskVo> taskList = new ArrayList<TaskVo>();

        // 获取媒体位标识
        RPlayer rPlayer = rPlayerObject.get(mac);
        if (rPlayer == null || rPlayer.getPositionId() == null) {
            throw new WayzException(ExceptionCode.PLAYER_UNREGISTER, "未登记的播控器:" + mac);
        }
        // 记录心跳
        if (ts != null) {
            heartbeat(mac, ts, st, planId, communicationType, signal);
        }

        // 如果有节目单任务
        if (rPlayer.getMenuId() != null && (!rPlayer.getMenuId().equals(menuId) || true == isInitial)) {
            TaskVo task = new TaskVo();
            task.setId(rPlayer.getMenuId());
            task.setType(CTaskType.UPDATE_MENU.getValue());
            task.setTaskId(rPlayer.getMenuId());
            taskList.add(task);
        }
        // 实时直播处理
        if (rPlayer.getLiveId() != null
                && (rPlayer.getIsLive() == null || rPlayer.getIsLive() == false || true == isInitial)) {
            TaskVo task = new TaskVo();
            task.setId(rPlayer.getLiveId());
            task.setType(CTaskType.START_LIVE.getValue());
            task.setTaskId(rPlayer.getLiveId());
            taskList.add(task);
        }
        // 直播上屏处理
        if (rPlayer.getLivePlanId() != null
                && (rPlayer.getIsLive() == null || rPlayer.getIsLive() == false || true == isInitial)) {
            TaskVo task = new TaskVo();
            task.setId(rPlayer.getLivePlanId());
            task.setType(CTaskType.START_LIVE_PLAN.getValue());
            task.setTaskId(rPlayer.getLivePlanId());
            taskList.add(task);
        }
        // 紧急插播
        if (StringUtil.notEmpty(rPlayer.getEmergentId())) {
            TaskVo task = new TaskVo();
            task.setId(Long.parseLong(rPlayer.getEmergentId()));
            task.setType(CTaskType.UPDATE_EMERGENT.getValue());
            task.setTaskId(Long.parseLong(rPlayer.getEmergentId()));
            taskList.add(task);
        }
        // else if (true == isInitial) {
        // TODO 需要实现初始化, 从数据库中获取紧急插播
        // }
        // 素材换刊
        String idString = rPlayer.getScreenIds();
        if (!StringUtils.isEmpty(idString)) {
            String[] taskScreenIds = idString.split(",");
            for (String taskScreenId : taskScreenIds) {
                String[] ids = taskScreenId.split("-");
                TaskVo task = new TaskVo();
                task.setId(Long.parseLong(ids[0]));
                task.setType(CTaskType.DOWNLOAD_SCREEN_MATERIAL.getValue());
                task.setTaskId(Long.parseLong(ids[1]));
                taskList.add(task);
            }
        }

        // 返回数据
        return taskList;
    }


    /**
     * 上报心跳
     *
     * @param mac 播控设备有线网卡地址
     * @param ts 系统时间戳(精确到秒)
     * @param st 当前状态(0:空闲;1:正常播放;2:正在更新操作系统; 3:正在更新播放器程序)
     * @param menuId 当前播放的节目单标识
     * @param netType 网络类型(1:WiFi;2:3G;3:VPN;4:LAN)
     * @param signal 信号强度
     * @throws WayzException 平台异常
     */
    @Override
    public void heartbeat(String mac, Long ts, Short st, Long menuId, Short netType, Integer signal)
            throws WayzException {

        // 媒体位标识
        if (!rPlayerObject.exist(mac)) {
            LOGGER.error(MessageFormat.format("未登记的播控器:{0},发送心跳", mac));
            throw new WayzException(ExceptionCode.PLAYER_UNREGISTER, MessageFormat.format("未登记的播控器:{0}", mac));
        }

        // 初始化
        final DPlayHeartbeat playHeartbeatCreate = this.buildHeartbeat(mac, ts, st, menuId, netType, signal);
        //向mq中发送消息
        rabbitTemplate.convertAndSend(MqDefinition.PLAY_EXCHANGE,MqDefinition.PLAY_HEART_BEAT_ROUTING_KEY,JSON.toJSONString(playHeartbeatCreate));

        // 恢复无心跳告警
        if (rPlayerHeartbeatRank.get(mac) == null) {
            Long alertId = rPlayerObject.getLong(mac, RPlayer.HBALERTID);
            if (alertId != null) {
                // 设置告警状态
                DPlayAlert dPlayAlertModify = new DPlayAlert();
                dPlayAlertModify.setId(alertId);
                dPlayAlertModify.setIsRecover(true);
                dPlayAlertDAO.modify(dPlayAlertModify);
            }
            Boolean isOnline = rPlayerObject.getBoolean(mac, RPlayer.ISONLINE);
            if (isOnline == null || !isOnline) {
                // 设置播控器在线状态
                DPlayController dPlayControllerModify = new DPlayController();
                dPlayControllerModify.setCode(mac);
                dPlayControllerModify.setIsOnline(true);
                dPlayControllerDAO.modify(dPlayControllerModify);

                // 清除缓存中告警标识
                rPlayerObject.setBoolean(mac, RPlayer.ISONLINE, true);
                rPlayerObject.remove(mac, RPlayer.HBALERTID);
            }
        }
        Long sysTs = System.currentTimeMillis() / 1000;
        // 设置缓存
        rPlayerHeartbeatRank.set(mac, sysTs);
        rPlayerObject.setLong(mac, RPlayer.LASTHEARTBEATTIME, System.currentTimeMillis());
    }

    /**
     * 组装参数
     *
     * @param mac
     * @param ts
     * @param st
     * @param menuId
     * @param netType
     * @param signal
     * @return
     */
    private DPlayHeartbeat buildHeartbeat(String mac, Long ts, Short st, Long menuId, Short netType,
                                                Integer signal) {
        DPlayHeartbeat playHeartbeatCreate = new DPlayHeartbeat();
        // 创建心跳
        playHeartbeatCreate.setPlayCode(mac);
        if (ts != null) {
            playHeartbeatCreate.setTs(TimeHelper.getTimestamp(ts * 1000));
        }
        playHeartbeatCreate.setId(rPlayHeartbeatId.increment());
        playHeartbeatCreate.setStatus(st);
        playHeartbeatCreate.setMenuid(menuId);
        playHeartbeatCreate.setNetType(netType);
        playHeartbeatCreate.setRssi(signal);
        playHeartbeatCreate.setCreatedTime(TimeHelper.getTimestamp(System.currentTimeMillis()));
        return playHeartbeatCreate;
    }

    /**
     * 获取直播url
     *
     * @param mac 播控设备有线网卡MAC地址
     * @param taskId 播控任务标识
     * @return 直播url
     * @throws WayzException 平台异常
     */
    @Override
    public String getLiveUrl(String mac, Long taskId) throws WayzException {
        // 验证播控器合法性
        RPlayer rPlayer = rPlayerObject.get(mac);
        if (rPlayer == null || rPlayer.getPositionId() == null) {
            throw new WayzException(ExceptionCode.PLAYER_UNREGISTER, "未登记的播控器:" + mac);
        }

        // 查询
        String liveUrl = dRealtimeLiveDAO.getPullUrl(taskId);

        // 返回数据
        return liveUrl;
    }

    /**
     * 获取节目单任务
     *
     * @param mac 播控设备有线网卡MAC地址
     * @param taskId 播控任务标识
     * @return 节目单列表
     * @throws WayzException 平台异常
     */
    @Override
    public List<MenuVo> getMenu(String mac, Long taskId) throws WayzException {
        // 初始化
        List<MenuVo> menuList = new ArrayList<MenuVo>();

        // 验证播控器合法性
        RPlayer rPlayer = rPlayerObject.get(mac);
        if (rPlayer == null || rPlayer.getPositionId() == null) {
            throw new WayzException(ExceptionCode.PLAYER_UNREGISTER, "未登记的播控器:" + mac);
        }

        // 查询节目单
        // List<DPlayMenu> dPlayMenuList = dPlayMenuDAO.queryPlayMenu(taskId, rPlayer.getPositionId());
        List<DPlayMenu> dPlayMenuList = null;
        //String menuStr = readFileFromOss(getOssUrl(rPlayer.getPositionId(), taskId));
        String menuStr = readPlayMenuFile(getPlayMenuUrl(rPlayer.getPositionId(), taskId));
        if(!menuStr.isEmpty()){
            dPlayMenuList = JSONObject.parseArray(menuStr, DPlayMenu.class);
        }

        if (dPlayMenuList != null && dPlayMenuList.size() > 0) {
            // 依次赋值
            for (DPlayMenu dPlayMenu : dPlayMenuList) {
                // 初始化
                MenuVo menu = new MenuVo();

                // 设置参数
                menu.setId(dPlayMenu.getId());
                menu.setPlanId(dPlayMenu.getPlanId());
                menu.setScrId(dPlayMenu.getScreenId());
                menu.setStart(TimeHelper.getTime(dPlayMenu.getBegintime()));
                /*
                 * 暂时不用DSP广告 if (dPlayMenu.getIsIdle().booleanValue() == true) {
                 * menu.setIsIdle(true); } if (menu.getPlanId().compareTo(0L) <=
                 * 0) { menu.setIsMonitor(false); }
                 */
                menu.setDuration(dPlayMenu.getDuration());

                // 添加
                menuList.add(menu);
            }
        }

        // 返回数据
        return menuList;
    }

    /**
     * 读取本地服务器文件
     *
     * @param fileUrl 文件地址
     * @throws WayzException 异常
     */
    public String readPlayMenuFile(String fileUrl) throws WayzException {
        String jsonStr = "";
        File file = new File(fileUrl);
        if(file.exists()){
            // 读取文件内容
            try {
                // 获取输入流
                InputStream input = new FileInputStream(file);
                ByteArrayOutputStream result = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int length;
                while ((length = input.read(buffer)) != -1) {
                    result.write(buffer, 0, length);
                }
                jsonStr = result.toString("UTF-8");
                input.close();
            } catch (Exception e) {
                LOGGER.info("播控节目单文件(" + fileUrl + ")内容异常.", e);
                throw new WayzException("播控节目单文件内容异常", e);
            }

            // 打印提示信息
            LOGGER.info("播控节目单文件(" + fileUrl + ").");
        }else{
            // 打印提示信息
            LOGGER.info("无节目单文件(" + fileUrl + ").");
        }
        return jsonStr;
    }

    String getPlayMenuUrl (Long positionId, Long taskId){
        return playMenuSavePath + "/" + TimeHelper.getDate().replace("-", "") + "/" + positionId + "_" + taskId + ".json";
    }

}
